//
// Created by YellowStoneTech on 2018/10/23.
//
#include "com_joyson_app_jni_JniLib.h"
#include <android/log.h>
#include <proto/raknet.client.h>
#include <RakNetSources/RakPeerInterface.h>
#include <RakNetSources/RakAssert.h>
#include <RakNetSources/RakSleep.h>
#include <RakNetSources/MessageIdentifiers.h>
#include <RakNetSources/CheckSum.h>
#include <proto/cmd.h>

#define TAG "my-jni" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,TAG, __VA_ARGS__)


void connectToNet(JNIEnv *env) ;

void connectToNet();
JavaVM *g_VM;
jobject g_obj;
bool mNeedDetach;
JNIEXPORT jstring JNICALL Java_com_joyson_app_jni_JniLib_callFromC
        (JNIEnv *env, jclass jclas) {
    return env->NewStringUTF((char *) "Hello from JNI !");//C++用这种格式
}
JNIEnv* JNU_GetEnv() {
    JNIEnv* env;
    g_VM->GetEnv((void**)&env, JNI_VERSION_1_6);
//    g_VM->AttachCurrentThread((void **)&env, NULL);
    return env;
}
//现在存在问题，讲testDemo直接放在函数中执行下列方法没问题，但放在callback函数中有问题，需check
static void testDemo(){
    JNIEnv* env;
    bool isContect=false;
//    env=JNU_GetEnv();
    //获取当前native线程是否有没有被附加到jvm环境中
    int getEnvStat = g_VM->GetEnv((void **) &env,JNI_VERSION_1_6);
    if (getEnvStat == JNI_EDETACHED) {
        //如果没有， 主动附加到jvm环境中，获取到env
        if (g_VM->AttachCurrentThread(&env, NULL) != 0) {
            return;
        }
        mNeedDetach = JNI_TRUE;
    }
    //通过全局变量g_obj 获取到要回调的类
    jclass javaClass = env->GetObjectClass( g_obj);
    if (javaClass == 0) {
        LOGE("Unable to find class");
        g_VM->DetachCurrentThread();
        return;
    }
    if (env==NULL){
        LOGE("env指针为空");
        return;
    }
//    jstring h=env->NewStringUTF((char *) "Hello from JNI !");
//    LOGE("打印的值：%s",h);
//    //1.得到字节码
    jclass jclazz = env->FindClass("com/joyson/app/jni/JniLib");
    /**
     * 2.得到方法
     * jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
     * 最后一个参数是签名
     */
    jmethodID jmethodIDs = env->GetMethodID(jclazz,"isConntected","(Z)V");

    //3.实例化该类
    jobject jobject = env->AllocObject(jclazz);

    //4.调用方法
    env->CallVoidMethod(jobject,jmethodIDs,isContect);
    //成功调用了public int add(int x,int y)
//    printf("1.value===%d\n",value);
    LOGE("调用callbackIsContected");
    //释放当前线程
    if(mNeedDetach) {
        g_VM->DetachCurrentThread();
    }
    env = NULL;
}

void JNICALL Java_com_joyson_app_jni_JniLib_loginForRakNet
        (JNIEnv *env, jclass jclas) {
    //    //1.得到字节码
    //JavaVM是虚拟机在JNI中的表示，等下再其他线程回调java层需要用到
    env->GetJavaVM(&g_VM);
    // 生成一个全局引用保留下来，以便回调
    jobject jobject = env->AllocObject(jclas);
    g_obj = env->NewGlobalRef(jobject);
    LOGE("开始执行");
    connectToNet(env);
    LOGE("1.执行RakNet登陆");
//    testDemo();
    // Override point for customization after application launch.
}


//调用java方法，通知是否连接成功
static void callbackIsContected(JNIEnv *obj,jboolean isContect){
//    JNIEnv* env;
////    env=JNU_GetEnv();
//    //获取当前native线程是否有没有被附加到jvm环境中
//    int getEnvStat = g_VM->GetEnv((void **) &env,JNI_VERSION_1_6);
//    if (getEnvStat == JNI_EDETACHED) {
//        //如果没有， 主动附加到jvm环境中，获取到env
//        if (g_VM->AttachCurrentThread(&env, NULL) != 0) {
//            return;
//        }
//        mNeedDetach = JNI_TRUE;
//    }
//    //通过全局变量g_obj 获取到要回调的类
//    jclass javaClass = env->GetObjectClass( g_obj);
//    if (javaClass == 0) {
//        LOGE("Unable to find class");
//        g_VM->DetachCurrentThread();
//        return;
//    }
//    if (env==NULL){
//        LOGE("env指针为空");
//        return;
//    }
//    ---------------------------------------
    JNIEnv *env;
    JavaVM *jvm;
    int result, status;
    status = jvm->GetEnv((void**) &env, JNI_VERSION_1_2);
    if (status < 0) {
        JavaVMAttachArgs args;
        args.version = JNI_VERSION_1_2;
        args.name = "user";
        args.group = NULL;
        result = (jvm)->AttachCurrentThread((JNIEnv **) &env, &args);
        if (result < 0) {
            LOGE("event_dispatcher_log AttachCurrentThread failed");
        }
    }
//    jstring h=env->NewStringUTF((char *) "Hello from JNI !");
//    LOGE("打印的值：%s",h);
//    //1.得到字节码
    jclass jclazz = env->FindClass("com/joyson/app/jni/JniLib");
    /**
     * 2.得到方法
     * jmethodID GetMethodID(jclass clazz, const char* name, const char* sig)
     * 最后一个参数是签名
     */
    jmethodID jmethodIDs = env->GetMethodID(jclazz,"isConntected","(Z)V");

    //3.实例化该类
    jobject jobject = env->AllocObject(jclazz);

    //4.调用方法
    env->CallVoidMethod(jobject,jmethodIDs,isContect);
    //成功调用了public int add(int x,int y)
//    printf("1.value===%d\n",value);
    LOGE("调用callbackIsContected");
    //释放当前线程
    if(mNeedDetach) {
        g_VM->DetachCurrentThread();
    }
    env = NULL;
}

// 连接结果
static void on_connect(bool success, void* usr_data) {
    if (success) {
        // 成功
        LOGE("2.RakNet连接成功");
        callbackIsContected((JNIEnv*)usr_data, true);
    } else {
        // 失败
        connectToNet();
        LOGE("2.RakNet连接失败");
        callbackIsContected((JNIEnv*)usr_data, false);
    }
}

// 连接断开
static void on_disconnect(void* usr_data) {
    connectToNet();
    LOGE("2.RakNet连接断开");
}



// 收到消息
static bool on_recv(unsigned char cmd, unsigned char *data, int length, void* usr_data) {
    // 处理消息`
    switch (cmd) {
        case ID_CHAT_LOGON: {
            LOGE("3.RakNet收到消息：登陆");
//            chat_logon_resp pkg;
//            if (pkg.ParseFromArray(data, length)) {
//            }
            callbackIsContected((JNIEnv*)usr_data, true);
            break;
        }
        case ID_CHAT_MESSAGE:{
            LOGE("3.RakNet收到消息：聊天");
            break;
        }
    }

    return true;
}

JNIEXPORT void connectToNet(JNIEnv *env) {
    get_client().set_callback(on_connect, on_disconnect, on_recv);
    get_client().set_data(env);

    get_client().connect("192.168.0.163", 9987, "Rumpelstiltskin");
}
 void connectToNet() {
    get_client().set_callback(on_connect, on_disconnect, on_recv);
    get_client().connect("192.168.0.163", 9987,"Rumpelstiltskin");
}


static void connectToNet2() {
    get_client().set_callback(on_connect, on_disconnect, on_recv);
    get_client().connect("192.168.0.163", 9987, "Rumpelstiltskin");

//    chat_logon logon;
//    get_client().send(ID_CHAT_LOGON, logon);
}




static void deprecatedLogin(){
    RakNet::RakPeerInterface *rakPeer = RakNet::RakPeerInterface::GetInstance();
    RakNet::SocketDescriptor sd(0, 0);
    RakNet::StartupResult sr = rakPeer->Startup(32, &sd, 1);
    (void) sr;
    RakAssert(sr == SR_SUCCESS);
    RakNet::ConnectionAttemptResult car = rakPeer->Connect("192.168.0.163", 9987, "Rumpelstiltskin",
                                                           (int) strlen("Rumpelstiltskin"));
    (void) car;
    RakSleep(1000);
    RakNet::Packet *packet;
    for (packet = rakPeer->Receive(); packet; rakPeer->DeallocatePacket(
            packet), packet = rakPeer->Receive()) {
        if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) {
            LOGE("raknet 登陆成功");
//            printf("ID_CONNECTION_REQUEST_ACCEPTED");
        } else {
            LOGE("raknet 登陆失败 %c", packet->data[0]);
        }
    }
}





